package com.caochenlei.db.util;

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import javax.sql.DataSource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.caochenlei.db.exception.CannotGetJdbcConnectionException;
import com.caochenlei.db.exception.DatabaseMetaGetMetaException;

public class JDBCUtils {
	private static Logger logger = LoggerFactory.getLogger(JDBCUtils.class);

	public static void closeConnection(Connection con) {
		if (con != null) {
			try {
				logger.debug("close connection " + con + " " + con.hashCode());
				con.close();
			} catch (SQLException ex) {
				logger.debug("Could not close JDBC Connection", ex);
			} catch (Throwable ex) {
				logger.debug("Unexpected exception on closing JDBC Connection", ex);
			}
		}
	}

	public static Connection getConnection(DataSource dataSource) throws CannotGetJdbcConnectionException {
		Assert.notNull(dataSource, "no datasource can be find!");
		Connection con;
		try {
			con = dataSource.getConnection();
			con.isReadOnly();
			logger.debug("Get the connection " + con + " " + con.hashCode());
		} catch (SQLException e) {
			throw new CannotGetJdbcConnectionException("Could not get JDBC Connection", e);
		}
		return con;
	}

	public static void closeResultSet(ResultSet rs) {
		if (rs != null) {
			try {
				logger.debug("close ResultSet " + rs + " " + rs.hashCode());
				rs.close();
			} catch (SQLException ex) {
				logger.debug("Could not close JDBC ResultSet", ex);
			} catch (Throwable ex) {
				logger.debug("Unexpected exception on closing JDBC ResultSet", ex);
			}
		}
	}

	public static void closePreparedStatement(PreparedStatement rs) {
		if (rs != null) {
			try {
				logger.debug("close PreparedStatement " + rs + " " + rs.hashCode());
				rs.close();
			} catch (SQLException ex) {
				logger.debug("Could not close JDBC PreparedStatement", ex);
			} catch (Throwable ex) {
				logger.debug("Unexpected exception on closing JDBC PreparedStatement", ex);
			}
		}
	}

	public static <T> T query(DatabaseMetaData dbm, String sql, String exceptionMessage, ResultSetExtractor<T> rsExtractor, Object... args) {
		ResultSet rs = null;
		PreparedStatement st = null;
		try {
			Connection con = dbm.getConnection();
			st = con.prepareStatement(sql);
			for (int i = 1; i <= args.length; ++i) {
				st.setObject(i, args[i - 1]);
			}
			rs = st.executeQuery();
			return rsExtractor.extractData(rs);
		} catch (SQLException e) {
			throw new DatabaseMetaGetMetaException(exceptionMessage, e);
		} finally {
			JDBCUtils.closePreparedStatement(st);
			JDBCUtils.closeResultSet(rs);
		}
	}
}
